#ifndef __CACHEALLOC_H__
#define __CACHEALLOC_H__

#include "cacheThread.h"
#include "cachePage.h"


static void* cAlloc(size_t size)
{
    if(size > sizeClass::kMaxSize)
    {
        size_t size_class = sizeClass::getRoundUp(size);

        size_t pagenum = size_class >> PAGE_SHIFT;
        qSpan* sp = PageCache::getInstance()->getSpan(pagenum);
        if(!sp)
            return nullptr;
        
        sp->size_ = size_class;
        return reinterpret_cast<void*>(sp->pageid_ << PAGE_SHIFT);
    }
    else
    {
        threadCache* tc_data = threadCache::getThreadCache();
        if(tc_data)
        {
            tc_data->allocate(size);
        }
    }
}

static void cFree(void* ptr)
{
    //size_t pageid = reinterpret_cast<uintptr_t>(ptr) >> PAGE_SHIFT;
    qSpan* sp = PageCache::getInstance()->getSpanByPageid(ptr);
    if(sp)
    {
        if(sp->size_ > sizeClass::kMaxSize)
        {
            PageCache::getInstance()->systemFreePage(ptr, sp->size_);
        }
        else
        {
            threadCache* tc_data = threadCache::getThreadCache();
            if(tc_data)
            {
                tc_data->dellocate(ptr, sp->size_);
            }
        }
    }
}

class cacheAlloc
{
public:
#ifdef CUR_CACHE
    static void* operator new(size_t size)
    {
        std::cout << "operator new: " << size << std::endl;
        return cAlloc(size);
    }

    static void operator delete(void* ptr)
    {
        std::cout << "operator delete: " << ptr << std::endl;
        cFree(ptr);
    }
#endif
};

template<class T>
class tcAlloc
{
public:
    template<class...Args>
    T* operator()(Args&&...args)
    {
#ifdef CUR_CACHE
        size_t size = sizeof(T);
        void* ptr = cAlloc(size);
        if(ptr)
        {
            return new (ptr) T(std::forward<Args>(args)...);
        }
        return nullptr;
#else
        return new T(std::forward<Args>(args)...);
#endif 
    }
};

template<class T>
class tcFree
{
public:
    void* operator()(T* ptr)
    {
#ifdef CUR_CACHE
        ptr->~T();
        cFree(ptr);
#else
        delete ptr;
#endif 
    }
};

template<class T>
class tcAllocSize
{
public:
    template<class...Args>
    T* operator()(size_t size, Args&&...args)
    {
#ifdef CUR_CACHE
        size_t totalsize = sizeof(T) + size;
        void* ptr = cAlloc(totalsize);
        if(ptr)
        {
            return new (ptr) T(std::forward<Args>(args)...);
        }
        return nullptr;
#else
        return reinterpret_cast<T*>(malloc(totalsize));
#endif 
    }
};

template<class T>
class tcFreeSize
{
public:
    void* operator()(T* ptr)
    {
#ifdef CUR_CACHE
        ptr->~T();
        cFree(ptr);
#else
        free(ptr);
#endif 
    }
};


template<class T>
class tcAllocArray
{
public:
    template<class...Args>
    T* operator()(size_t num)
    {
#ifdef CUR_CACHE
        //多申请size_t 保存数组长度
        size_t size = num * sizeof(T) + sizeof(size_t);
        char* objStart = reinterpret_cast<char*>(cAlloc(size));
        if(objStart)
        {
            *reinterpret_cast<size_t*>(objStart) = num;
            T* arr = reinterpret_cast<T*>(objStart + sizeof(size_t));
            for(size_t i = 0; i < num; ++i)
            {
                new (&arr[i]) T();
            }

            return arr;
        }
        return nullptr;
#else
        return new T[num];
#endif 
    }
};

template<class T>
class tcFreeArray
{
public:
    void* operator()(T* ptr)
    {
#ifdef CUR_CACHE
        char* objStart = reinterpret_cast<char*>(ptr);
        //取长度
        size_t num = *reinterpret_cast<size_t*>(objStart - sizeof(size_t));
        for(size_t i = num; i > 0; --i)
        {
            ptr[i - 1].~T();
        }

        //回收内存
        cFree(objStart - sizeof(size_t));
#else
        delete[] ptr;
#endif 
    }
};




#define tcalloc(type, ...) tcAlloc<type>()(__VA_ARGS__)
#define tcfree(type, ptr) tcFree<type>()(ptr)

#define tcallocSize(type, size, ...) tcAllocSize<type>()(size, __VA_ARGS__)
#define tcfreeSize(type, ptr) tcFreeSize<type>()(ptr)

#define tcallocArray(type, num) tcAllocArray<type>()(num)
#define tcfreeArray(type, ptr) tcFreeArray<type>()(ptr)

#endif